//
//  MutexLockDemo.m
//  MultiperThreadTest02
//
//  Created by FelixYin on 2020/4/5.
//  Copyright © 2020 FelixYin. All rights reserved.
//

#import "MutexLockDemo.h"
#import <pthread.h>

@interface MutexLockDemo ()

//互斥锁
@property (nonatomic,assign) pthread_mutex_t moneyLock;
@property (nonatomic,assign) pthread_mutex_t ticketLock;
@property (nonatomic,assign) pthread_mutex_t otherLock;

@end

@implementation MutexLockDemo

- (instancetype)init
{
    self = [super init];
    if (self) {
        //初始化锁
        [self __initLock:&_moneyLock];
        [self __initLock:&_ticketLock];
        [self __initLock:&_otherLock]; //用于测试加锁的情况
    }
    return self;
}

//初始化锁
- (void) __initLock:(pthread_mutex_t *) lock{
    /*
     递归锁：允许同一个线程对同一个锁进行重复加锁（不同的线程是没法对同一锁进行加锁）
     
     */
    
    
    //初始化属性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
//  PTHREAD_MUTEX_DEFAULT (默认锁)  PTHREAD_MUTEX_RECURSIVE（递归锁）
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    
    //初始化锁
    pthread_mutex_init(lock, &attr);
    
    //销毁属性
    pthread_mutexattr_destroy(&attr);
    
}


// MARK 测试死锁,递归锁



/*
 
 当otherLock是默认锁时（PTHREAD_MUTEX_DEFAULT），test，test2中使用同一个锁 嵌套调用，造成死锁（解决死锁问题方法是 test2中使用其他的锁，就可以解决）
 
 死锁解决方案:
 
 方案1：
 test2中使用跟test中不一样的锁就可以
 
 方案2：
 test,test2中同一把锁，使用递归锁也可以解决死锁问题
 */

- (void) test{
    pthread_mutex_lock(&_otherLock);
    NSLog(@"Test1");
    [self test2];
    pthread_mutex_unlock(&_otherLock);
    NSLog(@"Test1 End");
}


- (void) test2{
    pthread_mutex_lock(&_otherLock);
    NSLog(@"Test 2");
    pthread_mutex_unlock(&_otherLock);
    NSLog(@"Test2 End");
}


//当出现 递归调用时，使用默认锁会造成死锁，使用递归锁可以解决（PTHREAD_MUTEX_RECURSIVE）
- (void) test3{
    pthread_mutex_lock(&_otherLock);
    NSLog(@"Test1");
    [self test3];
    pthread_mutex_unlock(&_otherLock);
    NSLog(@"Test1 End");
}

// MARK 重写父类方法

- (void)saveMoney{
    pthread_mutex_lock(&_moneyLock);
    [super saveMoney];
    pthread_mutex_unlock(&_moneyLock);
}

- (void)drawMoney{
    pthread_mutex_lock(&_moneyLock);
    [super drawMoney];
    pthread_mutex_unlock(&_moneyLock);
}

- (void)saleTicket{
    pthread_mutex_lock(&_moneyLock);
    [super saleTicket];
    pthread_mutex_unlock(&_moneyLock);
}

- (void)dealloc
{
    pthread_mutex_destroy(&_moneyLock);
    pthread_mutex_destroy(&_ticketLock);
    pthread_mutex_destroy(&_otherLock);
}

@end
